/*
 * Copyright (c) 2017,安徽皖通科技股份有限公司 All rights reserved.
 */
package com.wttech.dzzf.process.service.errordata;

import com.wtkj.vo.dzzf.base.kfwd.FundAccount;
import com.wtkj.vo.dzzf.share.staticvalue.CertifiType;
import com.wttech.dzzf.process.dao.ProcessUserInfoDao;
import com.wttech.dzzf.process.model.IntKeyValue;
import com.wttech.dzzf.process.service.user.UserDetailInfosCreatorService;
import com.wttech.dzzf.process.util.CertVerificationService;
import com.wttech.dzzf.process.util.CertVerificationService.CertifiTypeCheck;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

/**
 * 客户信息治理Service业务实现
 *
 * @author MaShibo
 * @date 2017年9月24日
 */
@Service
public class SaveErrorUserInfoService {


    private static final Logger LOGGER = LoggerFactory.getLogger(SaveErrorUserInfoService.class);

    private static final int DEFAULT_NUM = 20000;

    private ProcessUserInfoDao processUserInfoDao;

    @Resource
    private ThreadPoolTaskExecutor executor;

    @Resource
    private UserDetailInfosCreatorService userDetailInfosCreatorService;

    /**
     * 证件类型 <-> 对应客户信息数量List
     */
    private List<IntKeyValue> countList;

    @Autowired
    public SaveErrorUserInfoService(ProcessUserInfoDao processUserInfoDao) {
        this.processUserInfoDao = processUserInfoDao;
    }

    public void process() {

        LOGGER.info("开始进行客户信息治理......");
        countList = processUserInfoDao.queryFundAccountNumGroupbyCertifiType();
        LOGGER.info("证件类型 <--> 现存数量：{}", countList);

        processUserInfoDao.trucateErrorTable();

        processErrorCertifiTypeInfos();

        processIdCards();

        processOfficerCert();

        processPassPortCert();

        processArrivalCardCert();

        processTemporaryIdCards();

        processOrgCert();

        executor.shutdown();
    }

    /**
     * 剔除错误的证件类型
     */
    public void processErrorCertifiTypeInfos() {
        LOGGER.info("开始治理证件类型错误的客户信息..");
        List<FundAccount> certifiTypeErrorList = new ArrayList<FundAccount>();
        CertifiTypeCheck check = new CertifiTypeCheck();
        for (IntKeyValue kv : countList) {
            String certifiTypeName;
            if (!check.test(kv.getKey())) {
                certifiTypeName = "错误的证件类型-" + kv.getKey();
                Map<String, Object> conditions = new HashMap<String, Object>();
                conditions.put("certifiType", kv.getKey());
                certifiTypeErrorList.addAll(processUserInfoDao.queryFundAccountByConditions(conditions));
            } else {
                certifiTypeName = CertifiType.CertifiTypeMap.get(kv.getKey());
            }
            LOGGER.info("证件类型：{} <-> 存在数量：{} ", certifiTypeName, kv.getValue());
        }
        LOGGER.info("错误证件类型数量：{}", certifiTypeErrorList.size());
        try {
            processUserInfoDao.batchIntertErrorInfo(certifiTypeErrorList, 1);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    public void processIdCards() {
        LOGGER.info("开始治理证件类型为身份证的客户信息..");
        processErrorInfo(CertifiType.IDCARD, new CertVerificationService.IdCardCheck());
    }

    public void processOfficerCert() {
        LOGGER.info("开始治理证件类型为军官证的客户信息");
        processErrorInfo(CertifiType.OFFICERCARD, new CertVerificationService.OfficerCertCheck());
    }

    public void processPassPortCert() {
        LOGGER.info("开始治理证件类型为护照的客户信息");
        processErrorInfo(CertifiType.PASSPORT, new CertVerificationService.OfficerCertCheck());
    }

    public void processArrivalCardCert() {
        LOGGER.info("开始治理证件类型为入境证的客户信息");
        processErrorInfo(CertifiType.ARRIVALCARD, new CertVerificationService.OfficerCertCheck());
    }

    public void processTemporaryIdCards() {
        LOGGER.info("开始治理证件类型为临时身份证的客户信息");
        processErrorInfo(CertifiType.INTERIMIDCARD, new CertVerificationService.IdCardCheck());
    }

    public void processOrgCert() {
        LOGGER.info("开始治理证件类型为组织机构代码证的客户信息");
        processErrorInfo(CertifiType.ORGCODE, new CertVerificationService.OrgCertCheck());
    }

    private void processErrorInfo(int certifiType, CertVerificationService verificationService) {
        Map<String, Object> conditions = new HashMap<String, Object>();
        conditions.put("certifiType", certifiType);
        int totalNum = processUserInfoDao.queryFundAccountNumberByConditions(conditions);
        LOGGER.info("共【{}】条数据", totalNum);
        // 总共处理count次
        int total = (int) Math.ceil((double) totalNum / DEFAULT_NUM);
        LOGGER.info("共需要执行{}次", total);

        List<Future<Integer>> futures = new ArrayList<Future<Integer>>();
        for (int i = 0; i < total; i++) {
            Future<Integer> future = executor.submit(new SubThreadProcess(conditions, i + 1, verificationService));
            futures.add(future);
        }
        userDetailInfosCreatorService.getFutureResult(futures);
    }

    public class SubThreadProcess implements Callable<Integer> {


        /**
         * 查询条件
         */
        private Map<String, Object> conditions;

        /**
         * 第count次执行
         */
        private int count;

        /**
         * 检验服务对象
         */
        private CertVerificationService check;

        public SubThreadProcess(Map<String, Object> conditions, int count, CertVerificationService check) {
            super();
            this.conditions = conditions;
            this.check = check;
            this.count = count;
        }

        @Override
        public Integer call() {
            LOGGER.info("第{}次，开始执行...", count);
            List<FundAccount> checkList = new ArrayList<FundAccount>();
            int startRow = (count - 1) * DEFAULT_NUM + 1;
            int endRow = count * DEFAULT_NUM;
            try {
                checkList = processUserInfoDao.queryFundAccountByPageInfo(conditions, startRow, endRow);
            } catch (Exception e1) {
                LOGGER.error(e1.getMessage(), e1);
            }
            List<FundAccount> errorInfos = null;
            for (FundAccount fundAccount : checkList) {
                if (!check.test(fundAccount.getCompanyLic())) {
                    if (errorInfos == null) {
                        errorInfos = new ArrayList<>();
                    }
                    errorInfos.add(fundAccount);
                }
            }
            // 证件号错误
            try {
                processUserInfoDao.batchIntertErrorInfo(errorInfos, 2);
            } catch (Exception e) {
                LOGGER.error(e.getMessage(), e);
            }
            LOGGER.info("第{}次，结束执行...", count);
            return checkList.size();
        }

    }

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        SaveErrorUserInfoService service = context.getBean(SaveErrorUserInfoService.class);
        service.process();
    }

}
